#-*- coding: utf-8 -*-
"""
bin2dec - binary numbers parsing functions
by Guillaume HUYSMANS, 2013.
"""

def bin2dec(s):
    """
    Reads an integer number from its binary representation
    
    Usage example (and testing procedure):
    >>> bin2dec('')
    0
    >>> bin2dec('000')
    0
    >>> bin2dec('11x010')
    Traceback (most recent call last):
    ...
    TypeError: s doesn't represent any valid integer binary number
    >>> bin2dec('101010')
    42
    """
    w = 1 #weight of the current digit
    v = 0 #accumulator
    for c in reversed(s):
        if c == '1':
            v += w
        elif c != '0':
            raise(TypeError("s doesn't represent any valid integer binary number"))
        w *= 2 #shift left...
    return v

def bin2dec_f(s):
    """
    Reads a (non-)integer number from its binary representation
    
    Usage example (and testing procedure):
    >>> bin2dec_f('')
    0.0
    >>> bin2dec_f('000')
    0.0
    >>> bin2dec_f('.')
    0.0
    >>> bin2dec_f('1.')
    1.0
    >>> bin2dec_f('101010')
    42.0
    >>> bin2dec_f('.101')
    0.625
    >>> bin2dec_f('.101.111')
    Traceback (most recent call last):
    ...
    TypeError: s contains too much decimal separators!
    >>> bin2dec_f('1x1101')
    Traceback (most recent call last):
    ...
    TypeError: s doesn't represent any valid binary number
    """
    #Get the position of the decimal separator to determine
    #the weight of the first digit
    p = s.find('.')
    if p == -1: #not found?
        p = len(s) #let's use the length of the whole string
    w = float(2 ** (p-1))
    sep = False
    #Accumulator
    v = 0.0 #we have to return a float even if we're parsing an empty string
    for c in s:
        if c == '1':
            v += w
            w /= 2 #shift right
        elif c == '0':
            w /= 2 #shift right
        elif c == '.':
            if sep:
                raise(TypeError("s contains too much decimal separators!"))
            sep = True
        else:
            raise(TypeError("s doesn't represent any valid binary number"))
    return v



if __name__ == "__main__":
    import doctest
    doctest.testmod(verbose=True)
